package net.lulihu.pangolin.headless.client.handler;

import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import net.lulihu.pangolin.headless.client.config.StartupConfig;
import net.lulihu.pangolin.headless.client.kit.PenetrateConfigKit;
import net.lulihu.pangolin.headless.common.container.Application;
import net.lulihu.pangolin.headless.common.container.annotation.Autowired;
import net.lulihu.pangolin.headless.common.container.annotation.Component;
import net.lulihu.pangolin.headless.common.functional.Consumer;
import net.lulihu.pangolin.headless.common.model.Penetrate;
import net.lulihu.pangolin.headless.common.model.PenetrateMapping;
import net.lulihu.pangolin.headless.common.protocol.ProtocolMessage;
import net.lulihu.pangolin.headless.common.protocol.ProtocolMessageType;
import net.lulihu.pangolin.headless.common.protocol.handler.RegistrationMessageTypeHandlerComponent;
import net.lulihu.pangolin.headless.common.util.FileKit;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 验证并申请代理端口结果消息处理程序
 */
@Slf4j
@Component
public class AuthAndApplyForAgentPortResultMessageHandler implements RegistrationMessageTypeHandlerComponent {

    @Autowired
    private StartupConfig startupConfig;

    @Override
    public byte[] messageTypes() {
        return new byte[]{
                ProtocolMessageType.S_AUTH_FAIL,
                ProtocolMessageType.S_PENETRATE
        };
    }

    @Override
    public void handle(ChannelHandlerContext context, ProtocolMessage message) {
        switch (message.getType()) {
            case ProtocolMessageType.S_PENETRATE:
                penetrateHandle(context, message);
                break;
            case ProtocolMessageType.S_AUTH_FAIL:
                authFailHandle(context, message);
                break;
            default:
                log.error("未定义的消息处理类型...");
                break;
        }
    }

    private void penetrateHandle(ChannelHandlerContext context, ProtocolMessage message) {
        if (log.isDebugEnabled()) log.debug("收到服务端返回申请穿透地址消息结果");

        final List<PenetrateMapping> mappings = message.getBodyList(PenetrateMapping.class);
        final String host = startupConfig.getHost();
        final List<Penetrate> penetrates = startupConfig.getPenetrates();

        addMainBodyAndWriteFile(lines -> {
            for (PenetrateMapping mapping : mappings) {
                String address = mapping.getAddress();
                Integer mappingPort = mapping.getMappingPort();
                if (mappingPort != null) {
                    lines.add("申请穿透地址:" + address + "  代理地址:" + host + ":" + mappingPort);

                    // 映射Id添加到启动配置的穿透数据中
                    for (Penetrate penetrate : penetrates) {
                        if (penetrate.getAddress().equals(address)) {
                            String mappingId = mapping.getMappingId();
                            penetrate.setMappingId(mappingId);
                        }
                    }
                } else {
                    lines.add("申请穿透地址:" + address + "  申请失败,原因为:" + mapping.getFailureReason());
                }
            }
        });

        // 写入系统临时文件 方便系统在重启时继续使用之前的映射Id
        PenetrateConfigKit.write(startupConfig.getPenetrates());
    }


    private void authFailHandle(ChannelHandlerContext context, ProtocolMessage message) {
        if (log.isDebugEnabled()) log.debug("收到服务端返回认证消息结果");

        addMainBodyAndWriteFile(lines -> lines.add(message.getBodyStr()));
        // 认证失败 程序停止
        Application.stop();
    }

    private void addMainBodyAndWriteFile(Consumer<List<String>> consumer) {
        List<String> lines = new ArrayList<>();
        lines.add("穿山甲 headless - v_" + startupConfig.getVersion());
        lines.add("");

        consumer.accept(lines);

        lines.add("");
        lines.add("注意:代理地址端口开启成功，并不代表可以真正使用，需要服务器防火墙开放该端口");

        // 写入文件
        try {
            FileKit.writeFile("申请穿透结果.txt", lines);
        } catch (IOException e) {
            log.error("穿透结果写入文件失败", e);
        }
    }

}
